<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>

  <script>

    /*
      两个术语: 函数/方法
         函数(function): 如果在JavaScript代码中通过function默认定义一个结构, 称之为是函数.
         方法(method): 如果将一个函数放到对象中, 作为对象的一个属性, 那么将这个函数称之为方法.
    */
    function foo() {
    }

    // key: 字符串类型, 但是在定义对象的属性名时, 大部分情况下引号都是可以省略的
    // 不能省略的情况 键名比较复杂的情况
    var person = {
      // key: value
      name: "Lily",
      age: 18,
      height: 1.88,
      "my friend": {
        name: "kobe",
        age: 30
      },
      run: function () {
        console.log("running")
      },
      eat: function () {
        console.log("eat foods")
      },
      study: function () {
        console.log("studying")
      }
    }

    // 1.对象字面量
    var obj1 = {
      name: "Lily"
    }

    // 2.new Object()
    // // Object构造函数
    // var obj2 = new Object()
    // obj2.name = "kobe"

    // // 3.new 其他类()
    // function Person() {}
    // var obj3 = new Person()

    // 1.定义了一个对象
    var info = {
      name: "Lily",
      age: 18,
      friend: {
        name: "kobe",
        age: 30
      },
      running: function () {
        console.log("running~")
      }
    }

    // 2.访问对象中的属性
    // console.log(info.name)
    // console.log(info.friend.name)
    // info.running()

    // 3.修改对象中的属性
    // info.age = 25
    // info.running = function() {
    //   alert("I am running~")
    // }
    // console.log(info.age)
    // info.running()

    // 4.添加对象中的属性
    info.height = 1.88
    info.studying = function () {
      console.log("I am studying~")
    }
    console.log(info)

    // 5.删除对象中的属性
    // delete关键字(操作符)
    delete info.age
    delete info.height
    console.log(info)

    // 对象中[]的使用 获取复杂的键值对（字符串定义的键名)
    var obj = {
      name: "Lily",
      "my friend": "kobe",
      "eating something": function () {
        console.log("eating~")
      }
    }

    console.log(obj["my friend"])
    console.log(obj.name)
    console.log(obj["name"])

    // obj["eating something"]()
    var eatKey = "eating something"
    obj[eatKey]()

    // 定义商品对象
    var product = {
      name: "鞋子",
      desc: "鞋子非常棒!!!",
      price: 99,
      brand: "nike"
    }

    // 定义手机对象
    var phone = {
      name: "iPhone 13 Pro Max",
      desc: "对iPhone的描述信息",
      price: 888,
      callPhone: function (phoneNum) {
        console.log("打电话给某人:", phoneNum)
      },
      playGame: function (gameName) {
        console.log("玩游戏:", gameName)
      }
    }

    // 定义用户对象
    var user = {
      id: 1111111,
      account: "张三",
      nickname: "张三",
      password: "xxx123",
      avatarURL: "图片地址",
      role: {
        id: 110,
        name: "管理员",
        createTime: "2033-03-03"
      }
    }

    var info = {
      name: "Lily",
      age: 18,
      height: 1.88
    }

    // console.log(Object.keys(info))

    // 对对象进行遍历
    // 1.普通for循环
    // 所有键名数组 Object.keys()
    var infoKeys = Object.keys(info)
    for (var i = 0; i < infoKeys.length; i++) {
      var key = infoKeys[i]
      var value = info[key]
      console.log(`key: ${key}, value: ${value}`)
    }

    // 2.for..in..: 遍历对象
    for (var key in info) {
      var value = info[key]
      console.log(`key: ${key}, value: ${value}`)
    }

    // 数组支持 for..of.. 可迭代对象
    // 对象不支持:  for..of..: 默认是不能遍历对象
    // for (var foo of info) {
    // }

    // 栈内存和堆内存
    // 原始数据类型：直接保存到栈内存中
    // 复杂数据类型：在堆内存中创建空间存储这个对象
    // 对象直接赋值：浅拷贝（将内存地址赋值），指向同一个对象

    // 值类型和引用类型
    // 值类型：原始类型
    // 引用类型：对象类型

    // 一些现象
    // var num1 = 123
    // var num2 = 123
    // console.log(num1 === num2)

    // 1.现象一: 两个对象的比较
    // var obj1 = {}  
    // var obj2 = {}
    // console.log(obj1 === obj2) //false


    // // 2.现象二: 引用的赋值
    // var info = {
    //   name: "Lily",
    //   friend: {
    //     name: "kobe"
    //   }
    // }

    // 对象引用赋值
    // var friend = info.friend
    // friend.name = "james"
    // console.log(info.friend.name) // james


    // 3.现象三: 值传递
    // function foo(a) {
    //   a = 200
    // }
    // var num = 100
    // foo(num)
    // console.log(num) // 100


    // 4.现象四: 引用传递, 但是在函数中创建了一个新对象, 没有对传入对象进行修改
    // function foo(a) {
    // a创建了一个新的对象 
    //   a = {
    //     name: "张三"
    //   }

    // }
    var obj = {
      name: "obj"
    }
    foo(obj)
    console.log(obj)

    // 5.现象五: 引用传递, 但是对传入的对象进行修改
    function foo(a) {
      // 访问a中的属性
      a.name = "Lily"
    }

    var obj = {
      name: "obj"
    }
    foo(obj)
    console.log(obj)

    // this指向
    // 函数中是有一个this的变量, this变量在大多数情况下会指向一个对象
    // arguments保存的是传入的所有参数

    // 情况一: 如果普通的函数被默认调用, 那么this指向的就是window
    // function foo(name, age) {
    //   console.log(arguments)
    //   console.log(this)
    // }
    // foo("abc", 123)

    function sayHello(name) {
      console.log(this)
    }


    // 情况二: 如果函数它是被某一个对象来引用并且调用它, 那么this会指向这个对象(调用的那个调用)
    // var obj = {
    //   name: "Lily",
    //   running: function() {
    //     console.log(this)
    //     // console.log(obj)
    //     // console.log(this === obj)
    //   }
    // }
    // obj.running()

    // 考验题目
    // 1.题目一:
    // var fn = obj.running
    // fn() // 默认调用就指向window

    // 2.题目二:
    function bar() {
      console.log('bar函数', this) // obj对象
    }
    var obj = {
      name: "Lily",
      bar: bar
    }
    obj.bar()
    bar()


    // this应用
    var info = {
      name: "张三",
      age: 18,
      running: function () {
        console.log("running~", this.name)
      },
      eating: function () {
        console.log("eating~", this.name)
      },
      studying: function () {
        console.log("studying~", this.name)
      }
    }

    info.running()
    info.eating()
    info.studying()

    // 以默认的方式调用的函数 this指向window
    // 以对象的方式调用 this指向调用的对象




  </script>

</body>

</html>